#!/usr/bin/env python
import re
import threading
import logging
from locale import getdefaultlocale

from myqq import *

def parse_cmdline():
    from optparse import OptionParser
    
    parser = OptionParser()
    
    parser.add_option("-u", "--uid")
    parser.add_option("-p", "--passwd")
    parser.add_option("--encoding")

    parser.add_option("-q", "--quiet", action="store_const",
                      const=logging.FATAL, dest="logLevel", default=logging.WARN)
    parser.add_option("-v", "--verbose", action="store_const",
                      const=logging.INFO, dest="logLevel")
    parser.add_option("-d", "--debug", action="store_const",
                      const=logging.DEBUG, dest="logLevel")
    parser.add_option("--log-format", dest="logFormat",
                      default="%(asctime)s %(levelname)s %(message)s")
    
    opts, args = parser.parse_args()
    
    return opts, args

def get_buddy_list(qq):
    list_lock(qq.buddy_list)
    try:
        for i in range(qq.buddy_list.count):
            yield get_buddy_item(qq.buddy_list, i)
    finally:
        list_unlock(qq.buddy_list)    

def get_qun_list(qq):
    list_lock(qq.qun_list)
    try:
        for i in range(qq.qun_list.count):
            yield get_qun_item(qq.qun_list, i)
    finally:
        list_unlock(qq.qun_list)    

def get_group_list(qq):
    list_lock(qq.group_list)
    try:
        for i in range(qq.group_list.count):
            yield get_group_item(qq.group_list, i)
    finally:
        list_unlock(qq.group_list)
        
def login(uid, passwd, mode=QQ_ONLINE):
    qq = qqclient()    
    
    qq_uid = opts.uid or raw_input("QQ#  : ")
    qq_passwd = opts.passwd or raw_input("pass : ")
    
    qqclient_create(qq, int(qq_uid), qq_passwd)
    
    qq.mode = mode
    
    qqclient_login(qq)
    
    print "loging...",
    
    while qq.process != P_LOGIN:
        qqclient_wait(qq, 1)
        
        if qq.process == P_LOGIN:
            print "succeeded."
            break
        elif qq.process == P_LOGGING:
            print ".",
        elif qq.process == P_VERIFYING:
            print 
            
            while True:
                captcha = raw_input("please input the captcha in verify folder: ")
            
                if len(captcha) == 4: break
                
                print "ERROR: captcha should be 4 chars"                    
            
            qqclient_verify(qq, captcha)
        elif qq.process == P_ERROR:
            print 
            print "ERROR: network failed."
            
            break
        elif qq.process == P_DENIED:
            print
            print "WARN: your QQ need be activated. (http://jihuo.qq.com)"
            
            break
        elif qq.process == P_WRONGPASS:
            print
            print "WARN: wrong password."
            
            break
        else:
            print
            print "ERROR: unknown error, %s" % qq.process
            
    return qq

def logout(qq):
    qqclient_logout(qq)
    qqclient_cleanup(qq)
    del qq
    
RE_MSG = re.compile(r"^buddymsg\^\$(?P<uid>\d+)\^\$(?P<time>[\d\s\-:]+)\^\$(?P<msg>.*)$")

def show_msg(qq, encoding):    
    while qq and qq.process == P_LOGIN:
        try:
            msg = get_message(qq, 1024, 1)
            
            if msg:
                msg = msg.decode('utf-8').encode(encoding)
                
                m = RE_MSG.match(msg)
                
                if m:
                    print "QQ#%d say (%s): %s" % (int(m.group('uid')), m.group('time'), m.group('msg'))
                    continue
                
                print msg
                
        except Exception, e:
            print "ERROR: fail to show message"
            print e
                
if __name__ == '__main__':
    opts, args = parse_cmdline()
    
    logging.basicConfig(level=opts.logLevel,
                        format=opts.logFormat)    
    
    config_init()
    qqsocket_init()    
    
    if opts.encoding is None:    
        lang, opts.encoding = getdefaultlocale()
        
        if opts.encoding is None:
            opts.encoding = 'gbk'
       
    qq_uid = opts.uid or raw_input("QQ#  : ")
    qq_passwd = opts.passwd or raw_input("pass : ")
        
    try:    
        qq = login(qq_uid, qq_passwd)
        
        t = threading.Thread(target=show_msg, args=(qq,opts.encoding,), name="show_msg")        
        t.setDaemon(True)
        t.start()
                
        while qq.process != P_INIT:
            line = raw_input(">").strip()
            
            if not line: continue
            
            cmd = line.split()[0]
            params = line[len(cmd)+1:].split()
            
            if cmd in ['exit', 'quit', 'e', 'q']:
                break
            
            elif cmd in ['login']:
                try:
                    if qq:
                        logout(qq)
                        qq = None
                    
                    qq = login(int(params[0]), params[1])
                    
                except (IndexError, TypeError):
                    print "login <QQ#> <password>"
            
            elif qq is None:
                print "WARN: please login QQ first"
                
            elif cmd in ['logout']:
                logout(qq)
                qq = None
            
            elif cmd in ['add', 'a']:
                try:
                    msg = ''.join(params[1:]).decode(opts.encoding).encode('utf-8')
                    
                    qqclient_add(qq, int(params[0]), msg)
                except (IndexError, TypeError):
                    print "add <QQ#> [message]"
                
            elif cmd in ['del', 'delete', 'd']:
                try:
                    qqclient_del(qq, int(params[0]))                    
                except (IndexError, TypeError), e:
                    print "del <QQ#>"
                    print e
                    
            elif cmd in ['say', 's']:
                try:
                    msg = ''.join(params[1:]).decode(opts.encoding).encode('utf-8')
                    
                    buddy_send_message(qq, int(params[0]), msg)
                    
                    if qqclient_wait(qq, 15) < 0:
                        print "WARN: fail to send message"
                except (IndexError, TypeError), e:
                    print "say <QQ#> <message>"
                    print e
                
            elif cmd in ['status']:
                if params:
                    for key, value in QQ_STATUS_NAMES.items():
                        if value == params[0]:
                            qqclient_change_status(qq, key)
                            break
                else:
                    print "QQ# %d <%s> is %s" % (qq.self.number,
                                                 qq.self.nickname,
                                                 QQ_STATUS_NAMES[int(qq.self.status)])
            elif cmd in ['update', 'u']:
                qun_update_all( qq );
                buddy_update_list( qq );
                group_update_list( qq );
                
            elif cmd in ['view', 'v']:
                if params:
                    pass
                else:
                    for buddy in get_buddy_list(qq):                    
                        print "QQ# %d <%s> is %s" % (buddy.number,
                                                     buddy.alias or buddy.nickname,
                                                     QQ_STATUS_NAMES[int(buddy.status)])
            elif cmd in ['group', 'g']:
                if params:
                    pass
                else:
                    for group in get_group_list(qq):
                        print "Group# %d <%s>" % (group.number, group.name)
                        
            elif cmd in ['qun']:
                if params:
                    pass
                else:
                    for qun in get_qun_list(qq):
                        print "Qun# %d.%d <%s> w/ %d members" % (qun.number,
                                                                 qun.ext_number,
                                                                 qun.name,
                                                                 qun.member_list.count)
            elif cmd in ['info', 'i']:
                for uid in params:
                    uid = int(uid)
                    buddy_update_info(qq, buddy_get(qq, uid, 0))
                    
                    if qqclient_wait( qq, 10 ) < 0:
                        print "WARN: fail to query #%d's information" % uid
                        
                    buddy = buddy_get(qq, uid, 0)
                    
                    print "Nickname     : %s" % buddy.nickname
                    print "UID          : %d" % buddy.number
                    print "Signature    : %s" % buddy.signature
                    print "Alias        : %s" % buddy.alias
                    print "Mobile       : %s" % buddy.mobilephone
                    print "Email        : %s" % buddy.email
                    print "Occupation   : %s" % buddy.occupation
                    print "Homepage     : %s" % buddy.homepage
                    print "School       : %s" % buddy.school
                    print "Country      : %s" % buddy.country
                    print "Province     : %s" % buddy.province
                    print "City         : %s" % buddy.city
                    print "Address      : %s" % buddy.address
                    print "Brief        : %s" % buddy.brief
                    print "Face         : %d" % buddy.face
                    print "Age          : %d" % buddy.age
                    print "Sex          : %s" % ("Male" if buddy.sex == 0 else "Female" if buddy.sex == 1 else "Asexual")
                    print "Status       : %s" % QQ_STATUS_NAMES[int(buddy.status)]
                
    finally:
        logout(qq)
        
        config_end()